package com.jevons.muffin.encrypt;

import android.text.TextUtils;
import android.util.Base64;

import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * AES加解密
 * <p/>
 * create at:  2016/8/25
 */
public final class AESCoder {

    //加密算法
    private static final String AES_MODE = "AES/CBC/PKCS7Padding";
    // 加密信息的编码方式
    private static final String CHARSET = "UTF-8";

    //AESCoder-ObjC uses SHA-256 (and so a 256-bit key)
    private static final String HASH_ALGORITHM = "SHA-256";

    //AESCoder-ObjC uses blank IV (not the best security, but the aim here is compatibility)
    private static final byte[] ivBytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    //默认生成密钥的的密码（随便敲得）
    public static final String DEFAULT_PASSWORD = "FDKF1jkfsa1208936343_jjds";

    /**
     * 通过SHA256哈希算法获取256位的加密密钥
     *
     * @param password 用于生成key
     * @return SecretKeySpec 256位的加密密钥
     */
    private static SecretKeySpec generateKey(String password) {
        if (TextUtils.isEmpty(password)) {
            password = DEFAULT_PASSWORD;
        }

        try {
            final MessageDigest digest = MessageDigest.getInstance(HASH_ALGORITHM);
            byte[] bytes = password.getBytes("UTF-8");
            digest.update(bytes, 0, bytes.length);
            byte[] key = digest.digest();
            SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
            return secretKeySpec;
        } catch (UnsupportedEncodingException e) {
            throw new IllegalArgumentException("AES生成SecretKey时找不到支持的编码格式," + e.getMessage());
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalArgumentException("AES生成SecretKey时找不到加解密算法," + e.getMessage());
        }
    }

    /**
     * 256位AES加密（加密结果经过Base64编码）
     *
     * @param password 用于生成秘钥的密码（自定义，加密和解密要保持一致）
     * @param message  加密的字符串(用UTF-8编码加密)
     * @return String 经过Base64编码的密文
     */
    public static String encrypt(String password, String message) {
        if (TextUtils.isEmpty(password)) {
            password = DEFAULT_PASSWORD;
        }

        try {
            final SecretKeySpec key = generateKey(password);
            byte[] cipherText = encrypt(key, ivBytes, message.getBytes(CHARSET));
            //NO_WRAP is important as was getting \n at the end
            String encoded = Base64.encodeToString(cipherText, Base64.NO_WRAP);
            return encoded;
        } catch (UnsupportedEncodingException e) {
            throw new IllegalArgumentException("AES加密找不到支持的编码格式," + e.getMessage());
        }
    }

    /**
     * 256位AES解密
     *
     * @param password                用于生成秘钥的密码（自定义，加密和解密要保持一致）
     * @param base64EncodedCipherText 解密信息--经过base64编码过的加密结果
     * @return String  解密结果（格式UTF-8）
     */
    public static String decrypt(String password, String base64EncodedCipherText) {
        if (TextUtils.isEmpty(password)) {
            password = DEFAULT_PASSWORD;
        }

        try {
            final SecretKeySpec key = generateKey(password);
            byte[] decodedCipherText = Base64.decode(base64EncodedCipherText, Base64.NO_WRAP);
            byte[] decryptedBytes = decrypt(key, ivBytes, decodedCipherText);
            String message = new String(decryptedBytes, CHARSET);
            return message;
        } catch (UnsupportedEncodingException e) {
            throw new IllegalArgumentException("AES解密找不到支持的编码格式," + e.getMessage());
        }
    }

    /**
     * AES加密(加密结果不经过任何编码)
     *
     * @param key     AES key 为128, 192或者 256 bit，也就是16/24/32bytes
     * @param iv      初始化向量参数，AES 为16bytes. DES 为8bytes
     * @param message byte[] 加密信息
     * @return byte[] 加密完的信息(没有经过编码)
     */
    public static byte[] encrypt(final SecretKeySpec key, final byte[] iv, final byte[] message) {

        try {
            final Cipher cipher = Cipher.getInstance(AES_MODE);
            IvParameterSpec ivSpec = new IvParameterSpec(iv);
            cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
            byte[] cipherText = cipher.doFinal(message);
            return cipherText;
        } catch (GeneralSecurityException e) {
            throw new IllegalArgumentException("AES加密异常," + e.getMessage());
        }
    }

    /**
     * AES解密
     *
     * @param key               AES key 为128, 192或者 256 bit，也就是16/24/32bytes
     * @param iv                初始化向量参数，AES 为16bytes. DES 为8bytes
     * @param decodedCipherText byte[] 解密信息
     * @return byte[] 解密完的信息
     */
    public static byte[] decrypt(final SecretKeySpec key, final byte[] iv, final byte[] decodedCipherText) {
        try {
            final Cipher cipher = Cipher.getInstance(AES_MODE);
            IvParameterSpec ivSpec = new IvParameterSpec(iv);
            cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
            byte[] decryptedBytes = cipher.doFinal(decodedCipherText);
            return decryptedBytes;
        } catch (GeneralSecurityException e) {
            throw new IllegalArgumentException("AES解密异常," + e.getMessage());
        }
    }

}
